def create_gobang_board(size=15):
    """
    创建五子棋棋盘（二维列表存储，初始为空格表示空点）
    :param size: 棋盘尺寸（线数，默认15）
    :return: 二维列表形式的棋盘
    """
    # 验证输入合法性
    if not isinstance(size, int) or size < 5:
        raise ValueError("棋盘尺寸必须是大于等于5的整数！")
    # 初始化棋盘：size x size 的二维列表，每个元素为空格（空落子点）
    return [[" " for _ in range(size)] for _ in range(size)]

def print_gobang_board(board):
    """
    打印五子棋棋盘（带坐标标识，兼容落子状态）
    :param board: 二维列表形式的棋盘
    """
    size = len(board)
    # 打印列坐标（顶部）：0 1 2 ... size-1
    print("  " + " ".join(str(col) for col in range(size)))
    # 打印棋盘顶部边框
    print(" +" + "---+" * size)
    # 打印每行内容（带行坐标）
    for row in range(size):
        # 打印竖线和落子点（当前行的棋子状态）
        print(f"{row}|" + "|".join(f" {board[row][col]} " for col in range(size)) + "|")
        # 打印横线分隔
        print(" +" + "---+" * size)

def is_valid_move(board, row, col):
    """
    检查落子是否合法
    :param board: 棋盘
    :param row: 落子行坐标
    :param col: 落子列坐标
    :return: 合法返回True，否则False
    """
    size = len(board)
    # 1. 坐标是否在棋盘范围内
    if row < 0 or row >= size or col < 0 or col >= size:
        print(f"错误：坐标({row},{col})超出棋盘范围！棋盘范围是(0-{size-1}, 0-{size-1})")
        return False
    # 2. 该位置是否已被占用
    if board[row][col] != " ":
        print(f"错误：坐标({row},{col})已被占用，请选择其他位置！")
        return False
    return True

def check_win(board, row, col, piece):
    """
    检查落子后是否获胜（五子连线判定）
    :param board: 棋盘
    :param row: 最新落子行坐标
    :param col: 最新落子列坐标
    :param piece: 棋子类型（"○" 或 "●"）
    :return: 获胜返回True，否则False
    """
    size = len(board)
    # 定义4个方向：水平、垂直、左上-右下、右上-左下（每个方向包含正负方向）
    directions = [(0, 1), (1, 0), (1, 1), (1, -1)]
    
    for dx, dy in directions:
        count = 1  # 当前落子算1个
        # 正向检查（例如水平向右、垂直向下等）
        for step in range(1, 5):
            x = row + dx * step
            y = col + dy * step
            if 0 <= x < size and 0 <= y < size and board[x][y] == piece:
                count += 1
            else:
                break
        # 反向检查（例如水平向左、垂直向上等）
        for step in range(1, 5):
            x = row - dx * step
            y = col - dy * step
            if 0 <= x < size and 0 <= y < size and board[x][y] == piece:
                count += 1
            else:
                break
        # 五子连线则获胜
        if count >= 5:
            return True
    return False

def gobang_game():
    """
    完整五子棋游戏主逻辑
    """
    print("===== 五子棋游戏 =====")
    print("规则：黑白双方轮流落子，先形成五子连线（横、竖、斜）者获胜！")
    print("提示：坐标输入格式为 行号 列号（例如：7 7 表示棋盘中心）\n")
    
    # 1. 初始化棋盘（支持用户自定义尺寸）
    while True:
        user_input = input("请输入棋盘线数（直接回车使用默认15）：")
        if user_input.strip() == "":
            board_size = 15
            break
        try:
            board_size = int(user_input)
            if board_size >= 5:
                break
            else:
                print("请输入大于等于5的整数！")
        except ValueError:
            print("输入无效，请输入一个整数！")
    
    board = create_gobang_board(board_size)
    print(f"\n生成{board_size}x{board_size}的五子棋棋盘：")
    print_gobang_board(board)
    
    # 2. 游戏初始化：轮流落子（黑方先下，用"●"；白方后下，用"○"）
    current_player = "黑方"
    current_piece = "●"
    move_count = 0
    max_moves = board_size * board_size  # 棋盘满子则平局
    
    # 3. 游戏循环
    while move_count < max_moves:
        print(f"\n{current_player}（{current_piece}）落子：")
        # 获取用户输入的坐标
        while True:
            move_input = input("请输入落子坐标（行 列）：").strip()
            # 分割输入为行和列
            if not move_input:
                print("输入不能为空，请重新输入！")
                continue
            coords = move_input.split()
            if len(coords) != 2:
                print("输入格式错误！请输入 行号 列号（用空格分隔），例如：7 7")
                continue
            # 转换为整数坐标
            try:
                row = int(coords[0])
                col = int(coords[1])
                break
            except ValueError:
                print("坐标必须是整数！请重新输入！")
        
        # 检查落子是否合法
        if not is_valid_move(board, row, col):
            continue
        
        # 合法则落子（更新二维列表）
        board[row][col] = current_piece
        move_count += 1
        
        # 打印更新后的棋盘
        print("\n当前棋盘状态：")
        print_gobang_board(board)
        
        # 检查是否获胜（落子后才可能获胜，只需检查最新落子位置）
        if check_win(board, row, col, current_piece):
            print(f"\n🎉 恭喜{current_player}（{current_piece}）获胜！游戏结束！")
            return
        
        # 切换玩家
        current_player = "白方" if current_player == "黑方" else "黑方"
        current_piece = "○" if current_piece == "●" else "●"
    
    # 棋盘下满且无人获胜（平局）
    print("\n🤝 棋盘已满，双方握手言和！游戏结束！")

if __name__ == "__main__":
    gobang_game()